package com.yhb.service.impl;

import com.yhb.conf.ResultCode;
import com.yhb.dao.BalanceFlowMapper;
import com.yhb.dao.WithdrawFlowMapper;
import com.yhb.model.BalanceFlow;
import com.yhb.model.Card;
import com.yhb.model.User;
import com.yhb.model.WithdrawFlow;
import com.yhb.service.BalanceService;
import com.yhb.service.CardService;
import com.yhb.service.UserService;
import com.yhb.utils.DateUtils;
import com.yhb.utils.StringUtils;
import lombok.var;
import me.edzh.spring.bootstrap.service.ObjectiveStorageService;
import me.edzh.spring.bootstrap.utils.data.Excel;
import me.edzh.spring.bootstrap.utils.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BalanceServiceImpl implements BalanceService {
    private final static BigDecimal BONUS_EXCEPT_TAX_RATE = new BigDecimal("0.92");

    private final static BigDecimal WITHDRAW_FEE = BigDecimal.valueOf(2);
    @Autowired
    private BalanceFlowMapper balanceFlowMapper;

    @Autowired
    private WithdrawFlowMapper withdrawFlowMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private CardService cardService;

    @Qualifier("ossServiceImpl")
    @Autowired
    private ObjectiveStorageService objectiveStorageService;

    @Override
    public List<BalanceFlow> getUserBalanceTyped(String userId) {
        var flows = balanceFlowMapper.getUserBalance(userId);
        var cpsFlow = BalanceFlow.builder()
                .amount(BigDecimal.ZERO)
                .type(BalanceFlow.Type.CPS_BONUS)
                .build();
        var tradeFlow = BalanceFlow.builder()
                .amount(BigDecimal.ZERO)
                .type(BalanceFlow.Type.TRADING)
                .build();
        var activateFlow = BalanceFlow.builder()
                .amount(BigDecimal.ZERO)
                .type(BalanceFlow.Type.ACTIVATE_BONUS)
                .build();

        for (var f : flows) {
            switch (f.getType()) {
                case CPS_BONUS:
                case CPS_BONUS_WITHDRAW:
                    cpsFlow.setAmount(cpsFlow.getAmount().add(f.getAmount()));
                    break;
                case TRADING:
                case TRADING_WITHDRAW:
                    tradeFlow.setAmount(tradeFlow.getAmount().add(f.getAmount()));
                    break;
                case ACTIVATE_BONUS:
                case ACTIVATE_BONUS_WITHDRAW:
                    activateFlow.setAmount(activateFlow.getAmount().add(f.getAmount()));
                    break;
            }
        }
        return Arrays.asList(cpsFlow, tradeFlow, activateFlow);
    }

    @Override
    public void insertUserBalance(BalanceFlow balanceFlow) {
        switch (balanceFlow.getType()) {
            case CPS_BONUS:
            case TRADING:
            case ACTIVATE_BONUS:
                if (balanceFlow.getAmount().compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException(ResultCode.ERROR_PARAMETER_WRONG, "参数错误");
                }

                balanceFlow.setAmount(balanceFlow.getAmount().multiply(BONUS_EXCEPT_TAX_RATE));

                break;
            case CPS_BONUS_WITHDRAW:
            case TRADING_WITHDRAW:
            case ACTIVATE_BONUS_WITHDRAW:
                if (balanceFlow.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                    throw new ServiceException(ResultCode.ERROR_PARAMETER_WRONG, "参数错误");
                }

                break;
        }

        balanceFlowMapper.addFlow(balanceFlow);

    }

    @Override
    @Transactional
    public void commitWithDraw(User user, BigDecimal amount, BalanceFlow.Type type, String cardId) {
        BigDecimal balance;
        String desc;
        switch (type) {
            case CPS_BONUS_WITHDRAW:
                balance = balanceFlowMapper.getUserBalanceForType(user.getId(),
                        Arrays.asList(BalanceFlow.Type.CPS_BONUS,
                                BalanceFlow.Type.CPS_BONUS_WITHDRAW));

                desc = "提现CPS返佣";
                break;
            case TRADING_WITHDRAW:
                balance = balanceFlowMapper.getUserBalanceForType(user.getId(),
                        Arrays.asList(BalanceFlow.Type.TRADING,
                                BalanceFlow.Type.TRADING_WITHDRAW));
                desc = "提现支付业务奖金";
                break;

            case ACTIVATE_BONUS_WITHDRAW:
                balance = balanceFlowMapper.getUserBalanceForType(user.getId(),
                        Arrays.asList(BalanceFlow.Type.ACTIVATE_BONUS,
                                BalanceFlow.Type.ACTIVATE_BONUS_WITHDRAW));
                desc = "提现激活奖金";
                break;

            default:
                throw new ServiceException(ResultCode.ERROR_PARAMETER_WRONG, "参数错误");
        }

        if (BigDecimal.valueOf(5).compareTo(amount) > 0) {
            throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "金额必须大于5");
        }

        if (balance.compareTo(new BigDecimal(100)) <= 0) {
            throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "账户余额大于100时才可提现");
        }

        if (balance.compareTo(amount) < 0) {
            throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "账户余额不足");
        }

        var card = cardService.cardWithOwnerCheck(cardId, user.getId());

        if (card.getType() != Card.Type.DEBIT) {
            throw new ServiceException(ResultCode.ERROR_TOAST_ERR, "提现卡必须为储蓄卡");
        }
        var balanceFlow = BalanceFlow.builder()
                .userId(user.getId())
                .amount(BigDecimal.ZERO.subtract(amount))
                .type(type)
                .description(new HashMap<String, String>() {{
                    put("desc", desc);
                }})
                .build();
        balanceFlowMapper.addFlow(balanceFlow);

//        var withdrawFeeFlow = BalanceFlow.builder()
//                .userId(user.getId())
//                .amount(BigDecimal.ZERO.subtract(WITHDRAW_FEE))
//                .type(type)
//                .description(new HashMap<String, String>() {{
//                    put("desc", desc + "提现到账费");
//                }})
//                .build();
//        balanceFlowMapper.addFlow(withdrawFeeFlow);

        var withdrawFlow = WithdrawFlow.builder()
                .userId(user.getId())
                .amount(amount.subtract(WITHDRAW_FEE))
                .cardId(cardId)
                .status(WithdrawFlow.Status.CREATED)
                .relatedBalanceFlowId(balanceFlow.getId())
                .remitFee(WITHDRAW_FEE)
                .build();

        withdrawFlowMapper.addFlow(withdrawFlow);

    }

    @Override
    public List<BalanceFlow> balanceList(String userId) {
        return balanceFlowMapper.getUserBalance(userId).parallelStream().filter(f -> !f.getType().name().contains("WITHDRAW")).collect(Collectors.toList());
    }

    @Override
    public List<WithdrawFlow> withdrawList(String userId) {
        return withdrawFlowMapper.getUserFlows(userId).parallelStream()
                .peek(flow -> {
                    var card = cardService.card(flow.getCardId());
                    flow.setRemitCard(Card.builder()
                            .id(card.getId())
                            .bankName(card.getBankName())
                            .number(StringUtils.getMaskCardNumber(card.getNumber()))
                    .build());
                })
                .collect(Collectors.toList());
    }


    @Override
    public List<BalanceFlow> getBalance(BalanceFlow flow) {
        return Optional.ofNullable(balanceFlowMapper.getFlow(flow)).orElse(new ArrayList<>());
    }

    @Override
    public boolean hasPublishedIncome(BalanceFlow.Type type, String additionalInfo) {
        var res =  balanceFlowMapper.getFlowByTypeAdditionalInfo(type, additionalInfo);
        return res != null && res.size() != 0;
    }

    DecimalFormat df = new DecimalFormat("##.##");
    @Override
    public String withdrawListUrlForRange(Date start, Date end) {
        var withdraws = withdrawFlowMapper.getFlowsOfRange(start, end);
        var created = withdraws.parallelStream()
                .filter(w -> w.getStatus() == WithdrawFlow.Status.CREATED)
                .collect(Collectors.toList());



        BigDecimal totalAmount = BigDecimal.ZERO;
        int count = 0;
        List<List<String>> rows = new ArrayList<>();
        for (WithdrawFlow withdrawFlow : created) {
            var c = cardService.card(withdrawFlow.getCardId());
            var u = userService.getUser(withdrawFlow.getUserId());
            var uc = userService.getCertificate(withdrawFlow.getUserId());
            if (uc == null || c == null) {
                continue;
            }
            count ++;
            totalAmount = withdrawFlow.getAmount().add(totalAmount);
            rows.add(Arrays.asList(withdrawFlow.getId().replace("-", ""), c.getNumber(), c.getBankName(), uc.getName(), uc.getIdCode(), c.getPhoneNumber(), df.format(withdrawFlow.getAmount()), "提现款项"));
        }

        String flowId = DateUtils.getCurrentTimeString();
        Excel e = new Excel(Arrays.asList("批次号(必填)", "总笔数(必填)", "总金额(必填)"));
        e.addRow(Arrays.asList(flowId, count + "", df.format(totalAmount)));
        e.addRow(Arrays.asList("商户订单号","收款账号(必填)","收款银行(建议填写)","收款户名(必填)","身份证号(必填)","手机号","打款金额(必填)","打款备注"));
        for (var row : rows) {
            e.addRow(row);
        }

        var b = e.export();
        String key = "admin/withdraw/" + flowId + ".xlsx";
        objectiveStorageService.putObject(key, b);
        return objectiveStorageService.signUrl("https://private.static.ylmvip.cn/" + key);
    }

    @Override
    public BigDecimal userLifeTimeIncome(String userId) {
        return balanceFlowMapper.getUserBalanceForType(userId, Arrays.asList(BalanceFlow.Type.ACTIVATE_BONUS, BalanceFlow.Type.TRADING, BalanceFlow.Type.CPS_BONUS));
    }
}
